package com.hmall.search.utils;

import com.alibaba.fastjson.JSON;
import com.hmall.domain.doc.ItemDoc;
import com.hmall.domain.dto.ItemSearchDto;
import com.hmall.domain.dto.PageDTO;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.lucene.search.function.FunctionScoreQuery;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 多条件查询工具类
 *
 * @Author XiaoJiangShi
 * @Date 2022/8/11 15:19
 * @Blog blog.XiaoJiangShi.net/996.mba
 * @Description: 多条件查询工具类
 */
public class SearchByConditions {

    /**
     * 根据条件查询，包含基本查询、高亮、广告等
     *
     * @param request   search request 对象
     * @param searchDto 查询条件
     */
    public static void search(SearchRequest request, ItemSearchDto searchDto) {
        BoolQueryBuilder builder = new BoolQueryBuilder();
        //关键字，搜索框内容
        if (searchDto.getKey() != null && !"".equals(searchDto.getKey())) {
            builder.must(QueryBuilders.matchQuery("all", searchDto.getKey()));
        } else {
            builder.must(QueryBuilders.matchAllQuery());
        }
        //品牌参数条件过滤
        if (searchDto.getBrand() != null && !"".equals(searchDto.getBrand())) {
            builder.filter(QueryBuilders.termQuery("brand", searchDto.getBrand()));
        }
        //分类参数条件过滤
        if (searchDto.getCategory() != null && !"".equals(searchDto.getCategory())) {
            builder.filter(QueryBuilders.termQuery("category", searchDto.getCategory()));
        }
        //价格参数条件过滤
        if (searchDto.getMaxPrice() != null && searchDto.getMinPrice() != null) {
            builder.filter(QueryBuilders.rangeQuery("price").gte(searchDto.getMinPrice()).lte(searchDto.getMaxPrice()));
        }

        //算分控制
        FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery(
                //原始查询，相关性算分查询
                builder,
                //function score数组
                new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{
                        //其中一个function score 元素
                        new FunctionScoreQueryBuilder.FilterFunctionBuilder(
                                //过滤条件
                                QueryBuilders.termQuery("isAD", true),
                                //算分函数
                                ScoreFunctionBuilders.weightFactorFunction(100))})
                //算分模型
                .scoreMode(FunctionScoreQuery.ScoreMode.SUM);
        //添加入dsl中
        request.source().query(functionScoreQueryBuilder);
    }

    /**
     * 返回结果进行解析
     *
     * @param response 返回结果响应
     * @return 分页数据结果处理
     */
    public static PageDTO<ItemDoc> result(SearchResponse response) {
        List<ItemDoc> itemDocs = new ArrayList<>();
        long total = response.getTotalShards();

        SearchHit[] hits = response.getHits().getHits();
        for (SearchHit hit : hits) {
            String sourceAsString = hit.getSourceAsString();
            ItemDoc itemDoc = JSON.parseObject(sourceAsString, ItemDoc.class);
            //获取高亮结果，并进行解析
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            if (highlightFields != null && highlightFields.size() > 0) {
                //获取name的高亮结果，判断是否存在，存在即将结果覆盖itemDoc中
                HighlightField field1 = highlightFields.get("name");
                if (field1 != null) {
                    String name = field1.getFragments()[0].toString();
                    itemDoc.setName(name);
                }
                //获取brand的高亮结果，判断是否存在，如果存在，将brand的新值覆盖itemDoc
                HighlightField field2 = highlightFields.get("brand");
                if (field2 != null) {
                    String brand = field2.getFragments()[0].toString();
                    itemDoc.setBrand(brand);
                }
            }

            itemDocs.add(itemDoc);
        }
        PageDTO<ItemDoc> pageDTO = new PageDTO<>();
        pageDTO.setList(itemDocs);
        pageDTO.setTotal(total);

        return pageDTO;
    }
}

